package com.mrx.mxshell

import java.nio.charset.Charset
import kotlin.system.exitProcess

/**
 * 支持的命令 枚举类
 */
enum class Cmd : CmdVerify {
    /**
     * help 命令： 显示帮助
     */
    HELP {
        override fun getParamStatus() = ParamStatus.NO_DO_NOT_GIVE
        override fun doStuff(param: String?) {
            Utils.print(
                """
                可用命令 ( 不区分大小写 ):
                help                        显示此消息
                echo                        输出一条消息
                ls [path]                   显示目录下所有文件
                cf <fileName>               创建新文件 (空文件)
                cat <fileName>              查看文件内容
                cd [path]                   切换当前工作目录
                cp <srcFile> <dstFile>      将 srcFile 复制为 dstFile
                rm <fileName>               删除文件
                rmdir <dirName>             删除空目录
                find <filePattern>          在当前目录下递归查找文件命名规则符合 filePattern 的所有文件 (夹) 
                write <content> <dstFile>   将 content 写入到文件 dstFile 中 (以 UTF-8 编码)
                open <fileName>             使用记事本打开 fileName (仅限 Windows 平台)
                close <fileName>            关闭使用 open 命令打开的 fileName (仅限 Windows 平台)
                syscall <command> <param>   调用系统命令, 暂时只支持传递 [0-2] 个参数的命令
                exit [code]                 退出程序
                """.replaceIndent()
            )
        }
    },

    /**
     * echo 命令：输出一句话
     */
    ECHO {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.print(param!!)
        }
    },

    /**
     * ls 命令：显示当前目录下所有文件 ( 夹 )
     */
    LS {
        override fun getParamStatus() = ParamStatus.MAYBE_ONE_PARAM
        override fun doStuff(param: String?) {
            param?.toFile()?.let {
                when {
                    !it.exists() -> Utils.print("路径不存在！")
                    it.isFile -> Utils.print("该路径指向一个文件！")
                    // 当路径存在,并且不是文件时
                    else -> Utils.print(Utils.listFiles(it))
                }
                return
            }
            Utils.print(Utils.listFiles(Utils.currentPwd.toFile()))
        }
    },

    /**
     * cf 命令：创建文件
     */
    CF {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.getAbsPwd(param).toFile().let {
                when {
                    !it.parentFile.exists() || it.isDirectory -> Utils.print("路径有误！")
                    it.exists() -> Utils.print("文件已存在！")
                    else -> if (!it.createNewFile()) Utils.print("创建文件失败！")
                }
            }
        }
    },

    /**
     * cd 命令：切换工作路径
     */
    CD {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.getAbsPwd(param).toFile().let {
                when {
                    !it.exists() -> Utils.print("路径不存在！")
                    it.isFile -> Utils.print("路径非文件夹！")
                    else -> Utils.currentPwd = it.absolutePath
                }
            }
        }
    },

    /**
     * cp 命令：复制文件
     */
    CP {
        override fun getParamStatus() = ParamStatus.YES_TWO_PARAM
        override fun doStuff(param: String?) {
            throw IllegalAccessException("该命令需要两个参数, 请调用 params:Array<String> 的 duStuff !")
        }

        override fun doStuff(params: Array<String>) {
            val srcFile = Utils.getAbsPwd(params[0]).toFile()
            val dstFile = Utils.getAbsPwd(params[1]).toFile()
            when {
                !srcFile.exists() -> Utils.print("源文件不存在！")
                srcFile.isDirectory -> Utils.print("源文件不能是目录！")
                dstFile.exists() -> Utils.print("已存在同名目标文件！")
                dstFile.isDirectory -> Utils.print("已存在同名目标文件夹！")
                else -> srcFile.copyTo(dstFile)
            }
        }
    },

    /**
     * cat 命令：查看文件
     */
    CAT {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.getAbsPwd(param).toFile().let {
                Utils.print(it.readText())
            }
        }
    },

    /**
     * rm 命令：删除文件
     */
    RM {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            val newPath = Utils.getAbsPwd(param)
            // 删除给定目录下所有文件
            if (newPath.endsWith("*")) {
                val path = newPath.removeSuffix("*")
                val files = path.toFile().listFiles()!!
                val sb = StringBuilder()
                files.forEach {
                    if (it.isFile) {
                        sb.append("${it.absolutePath} ${if (it.delete()) "删除成功" else "删除失败"}").append("\n")
                    }
                }
                Utils.print(sb)
                return
            }
            // 删除指定文件
            newPath.toFile().let {
                when {
                    !it.exists() -> Utils.print("文件不存在！")
                    it.isDirectory -> Utils.print("请使用 rmdir 命令删除文件夹")
                    else -> Utils.print("${it.absolutePath} " + if (it.delete()) "文件删除失败！" else " 删除成功")
                }
            }
        }
    },

    /**
     * rmdir 命令：删除空文件夹
     */
    RMDIR {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.getAbsPwd(param).toFile().let {
                when {
                    !it.exists() -> Utils.print("文件不存在！")
                    else -> if (!it.delete()) Utils.print("文件删除失败, 请检查该目录下是否有文件！")
                }
            }
        }
    },

    /**
     * mkdir 命令：创建文件夹
     */
    MKDIR {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.getAbsPwd(param).toFile().let {
                when {
                    it.exists() -> Utils.print("已存在同名文件或目录！")
                    else -> Utils.print(if (it.mkdir()) "目录创建成功！" else "目录创建失败！")
                }
            }
        }

    },

    /**
     * find 命令：查找当前目录下所有包含该文件名的文件 (夹)
     */
    FIND {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            val pattern = param!!.replace("*", "\\\\*").toPattern()
            val sb = StringBuilder()
            Utils.recursionListFiles().forEach {
                if (pattern.matcher(it.name).find()) {
                    sb.append(it).append("\n")
                }
            }
            Utils.print(sb)
        }
    },

    /**
     * write 命令：写入一段文本到指定文件
     */
    WRITE {
        override fun getParamStatus() = ParamStatus.YES_TWO_PARAM
        override fun doStuff(param: String?) {
            throw IllegalAccessException("该命令需要两个参数, 请调用 params:Array<String> 的 duStuff !")
        }

        override fun doStuff(params: Array<String>) {
            val dstFileName = params.last()
            val dstFile = dstFileName.toFile()
            when {
                !dstFile.exists() -> {
                    if (!dstFile.createNewFile()) {
                        Utils.print("创建文件失败！")
                        return
                    }
                }
                dstFile.isDirectory -> {
                    Utils.print("目标文件是文件夹！")
                    return
                }
            }
            val sb = StringBuilder()
            for (param in params) {
                if (param != dstFileName)
                    sb.append(param)
            }
            dstFile.writeText(sb.toString(), Charset.forName("UTF-8"))
        }
    },

    /**
     * open 命令：调用系统程序打开文件
     */
    OPEN {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            Utils.getAbsPwd(param).toFile().let {
                when {
                    !it.exists() -> Utils.print("文件不存在！")
                    it.isDirectory -> Utils.print("该路径是文件夹！")
                    else -> {
                        Runtime.getRuntime().exec("notepad ${it.absolutePath}")
                        Utils.print("文件以打开！")
                    }
                }
            }
        }
    },

    /**
     * close 命令：关闭指定窗口
     */
    CLOSE {
        override fun getParamStatus() = ParamStatus.YES_ONLY_ONE
        override fun doStuff(param: String?) {
            val pb = ProcessBuilder(
                "tasklist",
                "/FI",
                "WINDOWTITLE eq $param - Notepad2-mod"
            )
            val res = pb.start().inputStream.bufferedReader(Charset.forName("GBK")).readText()
            val pattern = """\d{4,6}""".toRegex()
            pattern.find(res)?.let {
                val closeResult = Runtime.getRuntime()
                    .exec("taskkill /f /pid ${it.value}")
                    .inputStream.bufferedReader(Charset.forName("GBK")).readText()
                Utils.print(closeResult)
                return
            }
            throw IllegalArgumentException("该文件还未打开或已关闭！")
        }
    },

    SYSCALL {
        override fun getParamStatus() = ParamStatus.MAYBE_TWO_PARAM
        override fun doStuff(param: String?) {
            throw IllegalAccessException("该命令需要两个参数, 请调用 params:Array<String> 的 duStuff !")
        }

        override fun doStuff(params: Array<String>) {
            val pb = ProcessBuilder().apply {
                if (params.size == 1)
                    command("cmd", "/k", params[0])
                else
                    command("cmd", "/k", params[0], params[1])
            }
            Utils.exec {
                val br = pb.start().inputStream.bufferedReader(Charset.forName("GBK"))
                while (true) {
                    println(br.readLine())
                }
            }
        }
    },

    /**
     * exit 命令：退出程序
     */
    EXIT {
        override fun getParamStatus() = ParamStatus.MAYBE_ONE_PARAM
        override fun doStuff(param: String?) {
            param?.let {
                runCatching {
                    exitProcess(param.toInt())
                }.onFailure {
                    Utils.print("退出代码有误！")
                    exitProcess(-1)
                }
            }
            exitProcess(0)
        }
    }
}